﻿using Coolzon.UI.Core.Parts;
using Coolzon.UI.Core.Properties;
using Coolzon.UI.Core.Runtime.Script;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using RT = Coolzon.Metadata.Runtime;

namespace Coolzon.UI.Core
{
    /// <summary>
    /// 区域只能放在场景下面
    /// </summary>
    [XPartIcon("pack://application:,,,/CPPEI.Coolzon.UI;component/Images/PartIcons/区域.png")]
    [System.ComponentModel.DisplayName("区域")]
    public partial class Area : ContentControl, IComponent, IScriptHost, IPartContainer
    {
        /// <summary>
        /// 元数据
        /// </summary>
        private RT.Area _metadata;
        public RT.Area AreaMatadata
        {
            get
            {
                return _metadata;
            }
            set
            {
                _metadata = value;
            }
        }

        /// <summary>
        /// 场景中包含的子组件集合
        /// </summary>
        private List<Widget> _widgets;
        private Canvas _canvas;

        private AreaScriptObject _scriptObject;

        #region script events definition
        /// <summary>
        /// 被激活时调用的脚本方法名称
        /// 和EventCallbackOnActived互斥
        /// 这个通过xml文件来设置
        /// </summary>
        public string EventStringOnActived;
        /// <summary>
        /// 被激活时调用的回调方法
        /// 和EventStringOnActived互斥
        /// 这个通过javascript来设置
        /// </summary>
        public Func<object> EventCallbackOnActived;
        #endregion

        static Area()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(Area), new FrameworkPropertyMetadata(typeof(Area)));

        }

        public Area()
        {
            // 裁剪内容，超出的不显示
            this.ClipToBounds = true;

            //XHeader = DateTime.Now.Ticks.ToString();
            XIsShowHeader = true;
            XHeaderWidth = 75;
            XHeaderHeight = 20;
            XHeaderPadding = new Thickness(0);
            HeaderBackground = null;
            //this.Background = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.Red);

            _widgets = new List<Widget>();
            _canvas = new Canvas();
            this.Content = _canvas;
        }

        ///// <summary>
        ///// 添加子区域
        ///// </summary>
        ///// <param name="Area"></param>
        //public void AddArea(Area Area)
        //{
        //    this._subAreas.Add(Area);
        //    this.AddPart(Area);
        //}

        //protected override void OnPartAdded(Part part)
        //{
        //    if (part is Area)
        //    {
        //        this._subAreas.Add((Area)part);
        //    }
        //}

        #region implement IComponent

        public string XFullName { get; set; }

        public void Init(PartContext context)
        {
            // 加载区域的脚本事件
            this.EventStringOnActived = this.AreaMatadata.GetScriptEventValue(RT.ScriptEvent.OnActived);

            for(int index = 0; index<_widgets.Count; index++)
            {
                _widgets[index].Init(context);
            }
        }

        public void Active(PartContext context)
        {
            for (int index = 0; index < _widgets.Count; index++)
            {
                _widgets[index].Active(context);
            }

            if (!string.IsNullOrEmpty(EventStringOnActived))
            {
                context.ScriptEngine.Run(EventStringOnActived, this.GetScriptObject());
            }
        }

        public void Deactive()
        {
        }

        public void Destroy()
        {
            for (int index = 0; index < _widgets.Count; index++)
            {
                _widgets[index].Destroy();
            }

            //// 移除引用
            //for (int index = 0; index < _partCollection.Count; index++)
            //{
            //    _canvas.Children.Remove(_partCollection[index]);

            //    _partCollection[index].ParentPart = null;
            //}
            //_partCollection.Clear();
        }

        #endregion

        //protected override void OnRefresh()
        //{
        //    base.OnRefresh();
        //    if (_partCollection == null)
        //    {
        //        return;
        //    }
        //    for (int index = 0; index < _partCollection.Count; index++)
        //    {
        //        _partCollection[index].Refresh();
        //    }
        //}

        //public override Part GetPartAtPoint(Type type, Point pointInRoot, UIElement rootElement)
        //{
        //    if (Visibility != System.Windows.Visibility.Visible)
        //    {
        //        return null;
        //    }
            
        //    Part part = null;
        //    // Point absolutePoint = this.TranslatePoint(new Point(0, 0), rootElement);
        //    for (int index = 0; index < this._partCollection.Count; index++)
        //    {
        //        part = this._partCollection[index].GetPartAtPoint(type, pointInRoot, rootElement);
        //        if (part != null)
        //        {
        //            return part;
        //        }
        //    }
        //    return base.GetPartAtPoint(type, pointInRoot, rootElement);
        //}

        ///// <summary>
        ///// 测试是否x，y点是否命中了组件实例
        ///// </summary>
        ///// <param name="pointInScene">场景中的坐标点</param>
        ///// <returns></returns>
        //public override XHitResult XHitTest(Point pointInScene)
        //{
        //    if (Visibility != System.Windows.Visibility.Visible)
        //    {
        //        return new XHitResult(false, null, default(Point));
        //    }

        //    Point pos = this.XGetAbsolutePos();
        //    Size size = this.XGetSize();

        //    if (pointInScene.X >= pos.X
        //        && pointInScene.Y >= pos.Y
        //        && pointInScene.X <= pos.X + size.Width
        //        && pointInScene.Y <= pos.Y + size.Height)
        //    {
        //        for (int index = this._partCollection.Count - 1; index >= 0; index--)
        //        {
        //            XHitResult hitResult = this._partCollection[index].XHitTest(pointInScene);
        //            if (hitResult.IsSuccess)
        //            {
        //                return hitResult;
        //            }
        //        }
        //        return new XHitResult(true, this, new Point(pointInScene.X - pos.X, pointInScene.Y - pos.Y));
        //    }
        //    return new XHitResult(false, null, default(Point));
        //}

        ///// <summary>
        ///// 测试是否x，y点是否命中了组件实例
        ///// </summary>
        ///// <typeparam name="T">命中的组件必须属于这个类型</typeparam>
        ///// <param name="pointInScene">场景中的坐标点</param>
        ///// <returns></returns>
        //public override XHitResult XHitTest<T>(Point pointInScene)
        //{
        //    if (Visibility != System.Windows.Visibility.Visible)
        //    {
        //        return new XHitResult(false, null, default(Point));
        //    }

        //    Type type = typeof(T);
        //    Point pos = this.XGetAbsolutePos();
        //    Size size = this.XGetSize();

        //    if (pointInScene.X >= pos.X
        //        && pointInScene.Y >= pos.Y
        //        && pointInScene.X <= pos.X + size.Width
        //        && pointInScene.Y <= pos.Y + size.Height)
        //    {
        //        for (int index = this._partCollection.Count - 1; index >= 0; index--)
        //        {
        //            XHitResult hitResult = this._partCollection[index].XHitTest<T>(pointInScene);
        //            if (hitResult.IsSuccess)
        //            {
        //                return hitResult;
        //            }
        //        }
        //        if (this.GetType() == type || this.GetType().IsSubclassOf(type)
        //            || type.IsAssignableFrom(this.GetType()))
        //        {
        //            return new XHitResult(true, this, new Point(pointInScene.X - pos.X, pointInScene.Y - pos.Y));
        //        }
        //    }
        //    return new XHitResult(false, null, default(Point));
        //}

        public Point XGetContentPos()
        {
            if (this.XIsShowHeader)
            {
                return new Point(this.Padding.Left,
                    this.Padding.Top + this.XHeaderHeight + this.XHeaderPadding.Top + this.XHeaderPadding.Bottom);
            }
            else
            {
                return new Point(this.Padding.Left, this.Padding.Top);
            }
        }

        #region Implement IPartContainer

        public List<Widget> GetPartList()
        {
            return _widgets;
        }

        /// <summary>
        /// 添加子组件
        /// </summary>
        /// <param name="part"></param>
        public void AddPart(Widget part)
        {
            _widgets.Add(part);
            _canvas.Children.Add(part);
            Canvas.SetZIndex(part, _canvas.Children.Count - 1);
            Canvas.SetLeft(part, part.Left);
            Canvas.SetTop(part, part.Top);

            part.ParentPart = null;// this;
        }

        public void XRemovePart(Widget part)
        {
            _widgets.Remove(part);

            _canvas.Children.Remove(part);
        }

        /// <summary>
        /// 获取子组件
        /// </summary>
        /// <param name="partName"></param>
        /// <param name="isRecursive">是否递归</param>
        /// <returns></returns>
        public Widget GetChildPart(string partName, bool isRecursive)
        {
            return null;
            //return _widgets.GetChildPart(partName, isRecursive);
        }

        /// <summary>
        /// 根据类型来获取组件里包含的子组件
        /// </summary>
        /// <param name="isRecursive"></param>
        /// <returns></returns>
        public List<T> GetChildPartByType<T>(bool isRecursive)
        {
            return null;
            //return _widgets.GetChildPartByType<T>(isRecursive);
        }

        public bool ValidateChildType(Type childType)
        {
            if (childType == typeof(Area) || childType.IsSubclassOf(typeof(Area)))
            {
                return true;
            }
            else if (childType.IsSubclassOf(typeof(Widget)))
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// 获取实际的可存放组件的容器控件
        /// </summary>
        /// <returns></returns>
        public UIElement GetContentContainer()
        {
            return this._canvas;
        }

        public void BringPartTo(Widget part, int index)
        {
            XRemovePart(part);
            _widgets.Insert(index, part);

            _canvas.Children.Insert(index, part);
            Canvas.SetZIndex(part, index);

            Canvas.SetLeft(part, part.Left);
            Canvas.SetTop(part, part.Top);

            //part.ParentPart = this;
        }
        public int GetPartIndex(Widget part)
        {
            if (part != null)
            {
                for (int index = _widgets.Count - 1; index >= 0; index--)
                {
                    if (_widgets[index] == part)
                    {
                        return index;
                    }
                }
            }
            return -1;
        }

        public int GetSendToBackIndex(Widget part)
        {
            return 0;
            //if(part is Area)
            //{
            //    return 0;
            //}
            //else
            //{
            //    return _subAreas.Count;
            //}
        }

        public int GetBringToFrontIndex(Widget part)
        {
            //if (part is Area)
            //{
            //    return _subAreas.Count - 1;
            //}
            //else
            //{
            //    return _partCollection.Count - 1;
            //}
            return 0;
        }
        public int GetForwardIndex(Widget part)
        {
            //int index = GetPartIndex(part);
            //if (part is Area)
            //{
            //    return index < _subAreas.Count - 1 ? index + 1 : index;
            //}
            //else
            //{
            //    return index < _partCollection.Count - 1 ? index + 1 : index;
            //}
            return 0;
        }

        public int GetBackwardIndex(Widget part)
        {
            //int index = GetPartIndex(part);
            //if (part is Area)
            //{
            //    return index > 0 ? index - 1 : index;
            //}
            //else
            //{
            //    return index > _subAreas.Count ? index - 1 : index;
            //}
            return 0;
        }

        public Tuple<Point?, Point?, byte> GetAlignLinePoint(Widget part, double left = -1, double top = -1, double right = -1, double bottom = -1)
        {
            //00表示left和top，01表示right和top，10表示left和bottom，11表示right和bottom
            byte bDirection = 0;
            Point? leftOrRight = null;
            Point? topOrBottom = null;
            double minOffsetX = double.MaxValue;
            double minOffsetY = double.MaxValue;
            for (int index = 0; index < _widgets.Count; index++)
            {
                Widget destPart = _widgets[index];
                if (destPart != part)
                {
                    if(left >= 0)
                    {
                        if (Math.Abs(destPart.Left - left) < 2 && Math.Abs(destPart.Left - left) < minOffsetX)
                        {
                            minOffsetX = Math.Abs(destPart.Left - left);
                            leftOrRight = new Point(destPart.Left, destPart.Top + destPart.Height / 2);
                            bDirection &= 2;
                        }
                        else if(Math.Abs(destPart.Left + destPart.Width - left) < 2 && Math.Abs(destPart.Left + destPart.Width - left) < minOffsetX)
                        {
                            minOffsetX = Math.Abs(destPart.Left + destPart.Width - left);
                            leftOrRight = new Point(destPart.Left + destPart.Width, destPart.Top + destPart.Height / 2);
                            bDirection &= 2;
                        }
                    }
                    if(top >= 0)
                    {
                        if (Math.Abs(destPart.Top - top) < 2 && Math.Abs(destPart.Top - top) < minOffsetY)
                        {
                            minOffsetY = Math.Abs(destPart.Top - top);
                            topOrBottom = new Point(destPart.Left + destPart.Width / 2, destPart.Top);
                            bDirection &= 1;
                        }
                        else if (Math.Abs(destPart.Top + destPart.Height - top) < 2 && Math.Abs(destPart.Top + destPart.Height - top) < minOffsetY)
                        {
                            minOffsetY = Math.Abs(destPart.Top + destPart.Height - top);
                            topOrBottom = new Point(destPart.Left + destPart.Width / 2, destPart.Top + destPart.Height);
                            bDirection &= 1;
                        }
                    }
                    if (right >= 0)
                    {
                        if (Math.Abs(destPart.Left - right) < 2 && Math.Abs(destPart.Left - right) < minOffsetX)
                        {
                            minOffsetX = Math.Abs(destPart.Left - right);
                            leftOrRight = new Point(destPart.Left, destPart.Top + destPart.Height / 2);
                            bDirection |= 1;
                        }
                        else if (Math.Abs(destPart.Left + destPart.Width - right) < 2 && Math.Abs(destPart.Left + destPart.Width - right) < minOffsetX)
                        {
                            minOffsetX = Math.Abs(destPart.Left + destPart.Width - right);
                            leftOrRight = new Point(destPart.Left + destPart.Width, destPart.Top + destPart.Height / 2);
                            bDirection |= 1;
                        }
                    }
                    if (bottom >= 0)
                    {
                        if (Math.Abs(destPart.Top - bottom) < 2 && Math.Abs(destPart.Top - bottom) < minOffsetY)
                        {
                            minOffsetY = Math.Abs(destPart.Top - bottom);
                            topOrBottom = new Point(destPart.Left + destPart.Width / 2, destPart.Top);
                            bDirection |= 2;
                        }
                        else if (Math.Abs(destPart.Top + destPart.Height - bottom) < 2 && Math.Abs(destPart.Top + destPart.Height - bottom) < minOffsetY)
                        {
                            minOffsetY = Math.Abs(destPart.Top + destPart.Height - bottom);
                            topOrBottom = new Point(destPart.Left + destPart.Width / 2, destPart.Top + destPart.Height);
                            bDirection |= 2;
                        }
                    }
                }
            }
            return new Tuple<Point?, Point?, byte>(leftOrRight, topOrBottom, bDirection);
        }

        #endregion

        #region implement IScriptHost
        public object GetScriptObject()
        {
            if (_scriptObject == null)
            {
                _scriptObject = new AreaScriptObject(this);
            }
            return _scriptObject;
        }
        #endregion
    }
}
